#include "theaterconst.h"

/* Manager */
void main() {
	int tc;
	int tcb;
	int i;
	int b;
	int cc;
	int ccb;
	int tt;
	int ttb;
	int start;
	int wait;
	
	init();
	prints("Manager has finished initializing shared data.\n");
	prints("IT IS SAFE TO EXECUTE THE CLERKS AND CUSTOMERS!\n");
	
	while (1) {
	/*
		prints("Manager is deciding who to put on break...\n");
		/* break */
		tc = 0;
		tcb = 0;
		/* tc on break */
		/* tc no one in line */
		Acquire(tcLineLock);
		for(i = 0; i < NUM_TICKET_CLERKS; i++) {
			if (ReadMonitor(tcBreak, i) == 0) tc++;
		}
		if (tc > 1) {
			/* make sure someone's working */
			for(i = 0; i < NUM_TICKET_CLERKS; i++) {
				/* no one in line */
				if (ReadMonitor(tcState, i) == C_READY) {
					int b = Rand(5);
					if (b == 0) {
						Acquire(tcLock[i]);
						SetMonitor(tcState, i, C_BREAK);
						SetMonitor(tcBreak, i, 1);
						/* Acquire(outputLock); */
						prints("Manager has told TicketClerk "); print(i);
						prints(" to go on break.\n");
						/* Release(outputLock); */
						Signal(tcCV[i],tcLock[i]);
						Release(tcLock[i]);
						tcb = 1;
						break;
					}
				}
			}
			if (!tcb) {
				/* tc less than 3 in line */
				for(i = 0; i < NUM_TICKET_CLERKS; i++) {
					if (ReadMonitor(tcState, i) != C_BREAK && ReadMonitor(tcLineCount, i) < 3) {
						int b = Rand(5);
						if (b == 0) {
							SetMonitor(tcBreak, i, 1);
							/* Acquire(outputLock); */
							prints("Manager has told TicketClerk "); print(i);
							prints(" to go on break.\n");
							/* Release(outputLock); */
							tcb = 1;
							break;
						}
					}
				}
			}
 		}
		Release(tcLineLock);
		/* tc off break */
		tc = 0;
		Acquire(tcLineLock);
		for(i = 0; i < NUM_TICKET_CLERKS; i++) {
			if (ReadMonitor(tcState, i) == C_BREAK) tc++;
		}
		if (tc) {
			for(i = 0; i < NUM_TICKET_CLERKS; i++) {
				if (ReadMonitor(tcLineCount, i) >= 5) {
					/* make any tc off break */
					Signal(tcBreakCV, tcLineLock);
					break;
				}
			}
		}
		Release(tcLineLock);
		
		/* cc break */
		cc = 0;
		ccb = 0;
		/* cc on break. cc no one in line */
		Acquire(ccLineLock);
		for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
			if (ReadMonitor(ccBreak, i) == 0) cc++;
		}
		if (cc > 1) {
			for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
				if (ReadMonitor(ccState, i) == C_READY) {
					b = Rand(5);
					if (b == 0) {
						Acquire(ccLock[i]);
						SetMonitor(ccState, i, C_BREAK);
						SetMonitor(ccBreak, i, 1);
						/* Acquire(outputLock); */
						prints("Manager has told ConcessionClerk "); print(i);
						prints(" to go on break.\n");
						/* Release(outputLock); */
						Signal(ccCV[i], ccLock[i]);
						Release(ccLock[i]);
						ccb = 1;
						break;
					}
				}
			}
			if (!ccb) {
				/* cc less than 3 in line */
				for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
					if (ReadMonitor(ccState, i) != C_BREAK && ReadMonitor(ccLineCount, i) < 3) {
						int b = Rand(5);
						if (b == 0) {
							SetMonitor(ccBreak, i, 1);
							/* Acquire(outputLock); */
							prints("Manager has told ConcessionClerk "); print(i);
							prints(" to go on break.\n");
							/* Release(outputLock); */
							ccb = 1;
							break;
						}
					}
				}
			}
 		}
		Release(ccLineLock);
		/* cc off break */
		cc = 0;
		Acquire(ccLineLock);
		for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
			if (ReadMonitor(ccState, i) == C_BREAK) cc++;
		}
		if (cc) {
			for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
				if (ReadMonitor(ccLineCount, i) >= 5) {
					Signal(ccBreakCV, ccLineLock);
					break;
				}
			}
		}
		Release(ccLineLock);
		
		/* tt break */
		tt = 0;
		ttb = 0;
		/* tt on break. tt no one in line */
		Acquire(ttLineLock);
		for(i = 0; i < NUM_TICKET_TAKERS; i++) {
			if (ReadMonitor(ttBreak, i) == 0) tt++;
		}
		if (tt > 1) {
			for(i = 0; i < NUM_TICKET_TAKERS; i++) {
				if (ReadMonitor(ttState, i) == C_READY) {
					b = Rand(5);
					if (b == 0) {
						Acquire(ttLock[i]);
						SetMonitor(ttState, i, C_BREAK);
						SetMonitor(ttBreak, i, 1);
						/* Acquire(outputLock); */
						prints("Manager has told TicketTaker "); print(i);
						prints(" to go on break.\n");
						/* Release(outputLock); */
						Signal(ttCV[i], ttLock[i]);
						Release(ttLock[i]);
						ttb = 1;
						break;
					}
				}
			}
			if (!ttb) {
				/* tt less than 3 in line */
				for(i = 0; i < NUM_TICKET_TAKERS; i++) {
					if (ReadMonitor(ttState, i) != C_BREAK && ReadMonitor(ttLineCount, i) < 3) {
						int b = Rand(5);
						if (b == 0) {
							SetMonitor(ttBreak, i, 1);
							/* Acquire(outputLock); */
							prints("Manager has told TicketTaker "); print(i);
							prints(" to go on break.\n");
							/* Release(outputLock); */
							ttb = 1;
							break;
						}
					}
				}
			}
 		}
		Release(ttLineLock);
		/* tt off break */
		tt = 0;
		Acquire(ttLineLock);
		for(i = 0; i < NUM_TICKET_TAKERS; i++) {
			if (ReadMonitor(ttState, i) == C_BREAK) tt++;
		}
		if (tt) {
			for(i = 0; i < NUM_TICKET_TAKERS; i++) {
				if (ReadMonitor(ttLineCount, i) >= 5) {
					Signal(ttBreakCV, ttLineLock);
					break;
				}
			}
		}
		Release(ttLineLock);
		
		prints("Manager is deciding whether to start the movie...\n");
		/* collect money. start movie*/
		Acquire(ttLineLock);
		Acquire(movieLock);
		start = 0;
		for (i = 0; i < NUM_TICKET_TAKERS; i++) {
			if (ReadMonitor(ttStop, i) != 0) {
				start = 1;
				break;
			}
		}
		if (ReadMonitor(ttTicketTotal, 0) == NUM_CUSTOMERS) {
			/* no customers */			
			start = 1;
		}
		if (ReadMonitor(customerReadyWatchingMovie, 0) != ReadMonitor(ttTakenSeat, 0) || ReadMonitor(customerReadyWatchingMovie, 0) == 0) {
			/* make sure all customers sit */
			start = 0;
		}
		if (ReadMonitor(movieState, 0) != M_WAITING) {
			/* movie is not ready to start */
			start = 0;
		}
		if (start != 0) {	
			/* start the movie */
			Acquire(mtLock);
			/* Acquire(outputLock); */
			prints("Manager is telling the MovieTechnician to start the movie.\n");
			/* Release(outputLock); */
			Signal(mtCV, mtLock);
			Release(mtLock);
		}
		Release(movieLock);
		Release(ttLineLock);
		/* finish movie */
		Acquire(ttLineLock);
		Acquire(movieLock);
		if (ReadMonitor(movieState, 0) == M_FINISHED) {
			if (ReadMonitor(customerReadyWatchingMovie, 0) == 0) {
				/* all customers leaves. make movie waiting */
				SetMonitor(movieState, 0, M_WAITING);
				/* make ticket taker start taking */
				for(i = 0; i < NUM_TICKET_TAKERS; i++) {
					SetMonitor(ttStop, i, 0);
				}
				/* wake up all customers in the lobby */
				SetMonitor(ttTakenSeat, 0, 0);
				Broadcast(lobbyCV, ttLineLock);
			}
		}
		Release(movieLock);
		Release(ttLineLock);
		/* if all customers leave */
		Acquire(leaveMutex);
		if (NUM_CUSTOMERS == ReadMonitor(leaveCount, 0)) {
			Acquire(incomeMutex);
			/* Acquire(outputLock); */
			prints("Total money made by office $"); print(ReadMonitor(totalIncome, 0));
			prints(".00.\n");
			/* Release(outputLock); */
			for(i = 0; i < NUM_TICKET_CLERKS; i++) {
				/* Acquire(outputLock); */
				prints("Manager collected $"); print(ReadMonitor(tcIncome, i));
				prints(".00 from TicketClerk "); print(i);
				prints(".\n");
				/* Release(outputLock); */				
			}
			for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
				/* Acquire(outputLock); */
				prints("Manager collected $"); print(ReadMonitor(ccIncome, i));
				prints(".00 from ConcessionClerk "); print(i);
				prints(".\n");
				/* Release(outputLock); */				
			}
			Release(incomeMutex);
			Release(leaveMutex);
			break;
		}
		Release(leaveMutex);

		/* collect money */
		Acquire(incomeMutex);
		/* Acquire(outputLock); */
		prints("Total money made by office $"); print(ReadMonitor(totalIncome, 0));
		prints(".00.\n");
		/* Release(outputLock); */
		for(i = 0; i < NUM_TICKET_CLERKS; i++) {
			/* Acquire(outputLock); */
			prints("Manager collected $"); print(ReadMonitor(tcIncome, i));
			prints(".00 from TicketClerk "); print(i);
			prints(".\n");
			/* Release(outputLock); */
		}
		for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
			/* Acquire(outputLock); */
			prints("Manager collected $"); print(ReadMonitor(ccIncome, i));
			prints(".00 from ConcessionClerk "); print(i);
			prints(".\n");
			/* Release(outputLock); */				
		}
		Release(incomeMutex);
		Release(leaveMutex);
		/* wait time */
		wait = 50;
		for(i = 0; i < wait; i++) {
			Yield();
		}
	}
	
	prints("Manager thread is exiting...\n");
	Exit(0);
}